package edu.umb.cs.antmanager.manager;

import static edu.umb.cs.antmanager.common.Constants.*;

import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Scanner;

import com.healthmarketscience.rmiio.RemoteInputStream;
import com.healthmarketscience.rmiio.RemoteInputStreamClient;

import edu.umb.cs.antmanager.common.AgentInterface;
import edu.umb.cs.antmanager.common.MachineStatus;

/**
 * For <tt>ManagerControlGUI</tt> to start a thread to execute a task on a
 * agent, similar to <tt>AgentConnRunnable</tt>, after the execution finished.
 * send the result back to the gui.
 * 
 * @author 2009CS682-3UMB_AntManager
 * 
 */
public class AgentTaskRunner implements Runnable {

	private String agentName;
	private ManagerControlGUI gui;
	private int taskType;
	private String cmd;

	/**
	 * setting the task and agent for run.
	 * 
	 * @param agentName
	 *            agent's host name
	 * @param gui
	 *            <tt>ManagerControlGUI</tt> for call back
	 * @param taskType
	 *            what kind of task to execute.
	 */
	public AgentTaskRunner(String agentName, ManagerControlGUI gui, int taskType) {
		this.agentName = agentName;
		this.gui = gui;
		this.taskType = taskType;
	}

	/**
	 * setting the task, agent, and command for ant command line execution.
	 * 
	 * @param agentName
	 *            - agent's host name
	 * @param gui
	 *            - <tt>ManagerControlGUI</tt> for call back
	 * @param taskType
	 *            - what kind of task to execute.
	 * @param cmd
	 *            - Command line parameters
	 */
	public AgentTaskRunner(String agentName, ManagerControlGUI gui,
			int taskType, String cmd) {
		this(agentName, gui, taskType);
		this.cmd = cmd;
	}

	@Override
	/*
	 * Start the task
	 */
	public void run() {
		AgentInterface agent = getAgentConnector(agentName);
		try {
			if (agent != null) {
				if (taskType == TASK_TYPE_STATUS) {
					MachineStatus machineStatus = agent.getStatus();
					if (machineStatus != null)
						gui.appendResultText(agentName + ": "
								+ machineStatus.getStatus());
					else
						gui.appendResultText(agentName + ": offline");
				} else if (taskType == TASK_TYPE_SHUTDOWN) {
					gui.appendResultText("Shutdown Agent " + agentName);
					agent.shutDown();
				} else if (taskType == TASK_TYPE_RESTART) {
					gui.appendResultText("Restart Agent " + agentName);
					agent.restart();
				} else if (taskType == TASK_TYPE_LOG) {
					RemoteInputStream ris = agent.getRunningLog();
					if (ris != null) {
						try {
							Scanner reader = new Scanner(
									RemoteInputStreamClient.wrap(ris));
							while (reader.hasNextLine()) {
								gui.appendResultText(reader.nextLine());
							}
							ris.close(true);
						} catch (IOException e) {
							gui.appendResultText("Cannot open log file");
						}
					} else
						gui.appendResultText("Agent " + agentName
								+ " is not running any test.");
				} else if (taskType == TASK_TYPE_EXECUTE) {
					gui.appendResultText("Execute Command on Agent "
							+ agentName);
					RemoteInputStream ris = agent.executeCommand(cmd);
					try {
						if (ris == null) {
							gui
									.appendResultText("Can't get response, please make sure the agent is idle!");
							return;
						}
						Scanner reader = new Scanner(RemoteInputStreamClient
								.wrap(ris));
						while (reader.hasNextLine()) {
							gui.appendResultText(reader.nextLine());
						}
						ris.close(true);
					} catch (IOException e) {
						gui.appendResultText("Cannot get result from "
								+ agentName);
					}
				}
			}

		} catch (RemoteException e) {
			// Agent's registry is not accessible
			gui.appendResultText(agentName + ": offline");
			e.printStackTrace();
		}
	}

	/**
	 * Connect to the Agent
	 * 
	 * @param agentName
	 *            Agent machine name
	 * @return AgentInterface
	 */
	private AgentInterface getAgentConnector(String agentName) {
		try {
			return RMIServerConnector.createAgentConnector(agentName);
		} catch (RemoteException e) {
			gui.appendResultText(agentName + ": offline");
			System.err.println(e.getMessage());
			// Agent's registry is not accessible
		} catch (MalformedURLException e) {
			gui.appendResultText("System Error!");
			// the URL used to access the agent is incorrect see
			// RMIServerConnector for details
		} catch (NotBoundException e) {
			gui.appendResultText(agentName + ": offline");
			System.err.println(e.getMessage());
			// the agent is not binded to the registry
		}
		return null;
	}

}
